import java.io.*;
import java.net.*;

/**
 * GameManager class contains the main method
 * and will be the starting point for the server. 
 * @author Chris Fraser, Jean-Luc Richard
 *
 */
public class GameManager
{
	/**
	 * The default number of players in the game.
	 * We decided that two was an appropriate value
	 * for this.
	 */
	private static final int DEFAULT_NUMBER_PLAYERS = 2;
	
	/**
	 * The default port for the server to bind to if not
	 * passed one on the command line.
	 */
	private static final int DEFAULT_PORT = 4001;
	
	/**
	 * Used to communicate
	 */
	private Socket[] sockets;
	
	/**
	 * The port in which the ServerSocket will bind to
	 */
	private int port;
	
	/**
	 * The current player's number
	 */
	private int currentPlayer;
	
	/**
	 * Game object
	 */
	private SchwimmenGame game;
	
	/**
	 * Constructor method for the GameManager class
	 */
	public GameManager(int numPlayers, int port)
	{
		this.port = port;
		
		try
		{
			ServerSocket serverSocket = new ServerSocket(this.port);
			for (int i = 0; i < numPlayers; i++)
			{
				this.sockets[i] = serverSocket.accept();
			}
		} 
		catch (IOException e) 
		{
			Logger.error("Unable to bind to socket. Exiting.");
			System.exit(0);
		}
		
		this.game = new SchwimmenGame(numPlayers);
	}
	
	/**
	 * The method reads from sockets, checks the incoming message by
	 * calling the checkProtocol method.
	 */
	private void readSocket() throws IOException
	{
	
		String userInput;
		BufferedReader br = new BufferedReader(new InputStreamReader(sockets[this.currentPlayer - 1].getInputStream()));
		while ((userInput = br.readLine()) != null)
		{
			Logger.info("Protocol message from client: " + userInput);
		    String returnMessage = this.game.newAction(this, userInput, this.currentPlayer);
		    
		    if ( ( ! returnMessage.isEmpty()) || returnMessage != null)
		    {
		    	this.writeToSocket(returnMessage, this.currentPlayer, this.currentPlayer);
		    }
		    
		    try
		    {
				Thread.sleep(1000);
			} 
		    catch (InterruptedException e)
		    {
				Logger.error("Blew up sleeping - exiting.");
				System.exit(0);
			}
		}		
	}
	
	/**
	 * This method is used to send out data to the client through the protocol.
	 */
	public void writeToSocket(String protIn, int currentPlayer, int nextPlayer)
	{
		try 
		{
			PrintWriter out = new PrintWriter(sockets[currentPlayer - 1].getOutputStream(), true);
			out.println(protIn);
			Logger.info("Writing out: " + protIn);
			this.currentPlayer = nextPlayer;
		} 
		catch (IOException e) 
		{
			Logger.error("Unable to write out to socket.");
			System.exit(0);
		}
	}
	
	/**
	 * The main method for GameManager
	 * @param args
	 */
	public static void main(String[] args)
	{
		/*
		 * Validate that the arguments passed in from the command line are valid.
		 */

		int numPlayers = GameManager.DEFAULT_NUMBER_PLAYERS;
		
		try 
		{
			numPlayers = Integer.parseInt(args[0]);
		}
		catch (Exception e)
		{
			Logger.error("Unable to determine the number of players.");
			System.exit(0);
		}
		
		if (numPlayers > 4 || numPlayers < 2)
		{
			Logger.error("The number of players is greater than 4, or less than 2. Exiting.");
			System.exit(0);
		}
		
		int port = GameManager.DEFAULT_PORT;
		
		try
		{
			port = Integer.parseInt(args[1]);
		}
		
		catch (Exception e)
		{
			Logger.error("Unable to determine the port.");
			System.exit(0);
		}
				
		GameManager gm = new GameManager(numPlayers, port);		
		gm.game.startGame(gm);
		
		//Meat and potatoes of the game. Everything has been initalized at this
		//point. Start waiting for clients to connect.
		try 
		{
			gm.readSocket();
		} 
		catch (IOException e) 
		{
			Logger.error("Exception occured while reading socket, exiting.");
			System.exit(0);
		}
		
		//When the gm.readSocket() method ends, we need to close the sockets.
		try 
		{
			for (Socket socket : gm.sockets)
			{
				socket.close();
			}
		} 
		catch (IOException e) 
		{
			Logger.error("Unable to close socket, exiting");
			System.exit(0);
		}
	}

}
